package genetischeralgorithmus;

import java.awt.*;
import java.util.*;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
/**
 *
 * @author Dominik
 */
public class Algorithmus {

    protected Fitness fit1;
    protected Mutation mut1;
    protected Population pop1;
    protected Recombination recomb1;
    protected Selection selec1;
    protected GenetischerAlgorithmusView view;
    protected Print print1;
    protected Parameter param1;
    int placesCount;

    public Algorithmus(GenetischerAlgorithmusView view) {

        fit1 = new Fitness();
        mut1 = new Mutation();
        pop1 = new Population();
        recomb1 = new Recombination();
        print1 = new Print(view);

        placesCount = 0;
        this.view = view;
    }

    public void startTravelingSalesman() {



        param1 = new Parameter(view);
        selec1 = new Selection(param1);

        fit1.setupMatrix();
        //fit1.printDistanceMatrix();
        pop1.initialise(1, placesCount, param1.getStartPopulation());



        for (int i = 0; i < param1.getMaxGeneration(); i++) {
            //Erschafft neue Generation aus der alten
            pop1 = nextGeneration(pop1);
            
            
        }

            view.currGen.setText(""+param1.getMaxGeneration());
            view.currPopSize.setText(""+pop1.getEntities().length);
            view.currBest.setText(""+Math.round(selec1.getRankingArray(fit1.rate(pop1, 1))[0][0]));
             print1.printPath(pop1.entities[(int)(selec1.getRankingArray(fit1.rate(pop1, 1))[0][1])].getPath(), fit1.getPlaces());



    }

    public Population nextGeneration(Population pop) {


        LinkedList<Double> fitnessList = fit1.rate(pop1, 1);   //Liste mit Fitnesswerten (index=index bei entities)
        double[][] rankingArray = selec1.getRankingArray(fitnessList); // [Fitnesswert][index bei entities] aufsteigend sotiert (=bester am anfang)
        view.currBest.setText(rankingArray[0][1]+": "+rankingArray[0][0] );

        int elite = (int) (pop.getEntities().length * (param1.getElite() / 100.0));  //Anzahl der Entities,. die mit in die nächste Generation uebernommen werden
        int newPopulationSize = (int) (pop.getEntities().length * (1 + param1.getPopulationGrowth() / 100)); // neue groeße der Population
        if (newPopulationSize > param1.getMaxPopulationSize()) {
            newPopulationSize = param1.getMaxPopulationSize();  //Wachstumsbeschraenkung der Population beruecksichtigen
        }


        Population newPopulation = new Population(); // neue Generation
        Entity[] newEntities = new Entity[newPopulationSize];  //neues Array für Entity

        int p=0;
        int i = 0;
        int help = elite;
        while (help > 0) {  //uebernimmt die besten Loesungen
            if (pop.getEntities()[(int) (rankingArray[i][1])].getAge() < param1.getMaxEntityAge()) {  //zu alte Loesungen werden nicht uebernommen
                newEntities[i] = pop.getEntities()[(int) (rankingArray[i][1])];  //eintragen in neue Generation
                newEntities[i].setAge(newEntities[i].getAge() + 1); //eine Generation altern lassen.
                i++;
                help--;
            }            
        }

        Entity[][] RoulettePairs = selec1.getRoulettePairs(rankingArray, pop, (newPopulationSize - elite), rankingArray[rankingArray.length - 1][0]);

        Entity[] offspring = recomb1.crossover(RoulettePairs, param1.getRecombination());

        Entity[] mutatedOffspring = mut1.mutate(offspring, param1.getMutation(), param1.getMutationDegree());



        int k = 0;
        for (int j = elite; j < newEntities.length; j++) {
            newEntities[j] = mutatedOffspring[k++];
        }

        
        newPopulation.setEntities(newEntities);


        //test ausgabe des besten Zufallpfades
        view.canvas1.getGraphics().clearRect(0, 0, 500, 500);
       


        return newPopulation;
    }

    public void addPoint(Point p1) {
        fit1.addplace(p1); // übergibt den eingetragenen Punkt an die FitnessKlasse
        placesCount++;  //Anzahl der Orte zählt einen hoch
    }

    public void clear() {
        view.canvas1.getGraphics().clearRect(0, 0, 500, 500);
        view.destinationlist.setText("");
        pop1.clear();
        fit1.clear();
        placesCount = 0;
    }
}
